package tuanda.soict.firstsun.AbilityPackage;

import java.util.ArrayList;

import tuanda.soict.firstsun.DataPackage.AbilityDataSet;
import tuanda.soict.firstsun.DataPackage.AbilityList;
import tuanda.soict.firstsun.DataPackage.CommonConstants;
import tuanda.soict.firstsun.LogicPackage.AI_Part;
import tuanda.soict.firstsun.LogicPackage.Army;
import tuanda.soict.firstsun.LogicPackage.ArmyManager;
import tuanda.soict.firstsun.LogicPackage.Controllable;
import tuanda.soict.firstsun.LogicPackage.Coordinate;
import tuanda.soict.firstsun.LogicPackage.Group;
import tuanda.soict.firstsun.LogicPackage.Scenario;

/**
 * @author tuanda_soict_hut
 * @version 0.0.2
 * @since 7-10-2012
 */
public abstract class Ability implements Controllable, AbilityList,
		CommonConstants {

	protected int ID;
	protected String abilityName;
	protected int abilityRange;
	protected int abilityArea;
	protected Coordinate target;
	protected int abilityPoint;
	protected int abilityAffect;
	protected int abilityLevel;
	protected ArmyManager armyManager;

	public Ability(int id, String name, int range, int area, int affect) {
		setID(id);
		setName(name);
		setAbilityArea(area);
		setAbilityRange(range);
		setAbilityAffectTo(affect);
		setAbilityLevel(0);
		armyManager = new ArmyManager();
	}

	public Ability() {
		setID(NO_SKILL);
		setName("No_name");
		setAbilityArea(0);
		setAbilityRange(0);
		setAbilityAffectTo(AFFECT_BOTH);
		setAbilityLevel(0);
		armyManager = new ArmyManager();
	}

	public Ability(Ability abil) {
		setID(abil.getID());
		setName(abil.getName());
		setAbilityArea(abil.getAbilityArea());
		setAbilityRange(abil.getAbilityRange());
		setTarget(abil.getTarget());
		setAbilityPoint(abil.getAbilityPoint());
		setAbilityAffectTo(abil.getAbilityAffectTo());
		setAbilityLevel(0);
		armyManager = new ArmyManager();
	}

	@Override
	public final String getName() {
		return this.abilityName;
	}

	@Override
	public final void setName(String name) {
		this.abilityName = name;
	}

	@Override
	public final int getID() {
		return this.ID;
	}

	@Override
	public final void setID(int id) {
		this.ID = id;
	}

	public final int getAbilityArea() {
		return this.abilityArea;
	}

	public final void setAbilityArea(int are) {
		this.abilityArea = are;
	}

	public final int getAbilityRange() {
		return this.abilityRange;
	}

	public final void setAbilityRange(int range) {
		this.abilityRange = range;
	}

	public final int getAbilityPoint() {
		return this.abilityPoint;
	}

	public final void setAbilityPoint(int point) {
		this.abilityPoint = point;
	}

	public final Coordinate getTarget() {
		return this.target;
	}

	public final void setTarget(Coordinate coor) {
		this.target = coor;
	}

	public final int getAbilityAffectTo() {
		return this.abilityAffect;
	}

	public final void setAbilityAffectTo(int affect) {
		this.abilityAffect = affect;
	}

	public final int getAbilityLevel() {
		return abilityLevel;
	}

	public final void setAbilityLevel(int level) {
		if (level > -1 && level < 6) {
			this.abilityLevel = level;
		}
	}

	public final ArmyManager getLevelUpManager() {
		return this.armyManager;
	}

	public static Ability abilityInitializer(AbilityDataSet ability) {
		int ID = ability.getID();
		switch (ID) {
		case BLESS:
			return new Bless_Ability(ID, ability.getName(),
					ability.getAbilityRange(), ability.getAbilityArea(),
					ability.getAbilityAffect());
		case CURE:
			return new Cure_Ability(ID, ability.getName(),
					ability.getAbilityRange(), ability.getAbilityArea(),
					ability.getAbilityAffect());
		case HASTE:
			return new Haste_Ability(ID, ability.getName(),
					ability.getAbilityRange(), ability.getAbilityArea(),
					ability.getAbilityAffect());
		case PRAY:
			return new Pray_Ability(ID, ability.getName(),
					ability.getAbilityRange(), ability.getAbilityArea(),
					ability.getAbilityAffect());
		case LIGHTNING:
			return new Lightning_Ability(ID, ability.getName(),
					ability.getAbilityRange(), ability.getAbilityArea(),
					ability.getAbilityAffect());
		case FIREBALL:
			return new Fireball_Ability(ID, ability.getName(),
					ability.getAbilityRange(), ability.getAbilityArea(),
					ability.getAbilityAffect());
		case EARTHQUAKE:
			return new Earthquake_Ability(ID, ability.getName(),
					ability.getAbilityRange(), ability.getAbilityArea(),
					ability.getAbilityAffect());
		case BLIZZARD:
			return new Blizzard_Ability(ID, ability.getName(),
					ability.getAbilityRange(), ability.getAbilityArea(),
					ability.getAbilityAffect());
		case DEFEND:
			return new Defend_Ability(ID, ability.getName(),
					ability.getAbilityRange(), ability.getAbilityArea(),
					ability.getAbilityAffect());
		case RUN:
			return new Run_Ability(ID, ability.getName(),
					ability.getAbilityRange(), ability.getAbilityArea(),
					ability.getAbilityAffect());
		case CHARGE:
			return new Charge_Ability(ID, ability.getName(),
					ability.getAbilityRange(), ability.getAbilityArea(),
					ability.getAbilityAffect());
		case CONCENTRATE:
			return new Concentrate_Ability(ID, ability.getName(),
					ability.getAbilityRange(), ability.getAbilityArea(),
					ability.getAbilityAffect());
		case FIRST_AID:
			return new FirstAid_Ability(ID, ability.getName(),
					ability.getAbilityRange(), ability.getAbilityArea(),
					ability.getAbilityAffect());
		case CURSE:
			return new Curse_Ability(ID, ability.getName(),
					ability.getAbilityRange(), ability.getAbilityArea(),
					ability.getAbilityAffect());
		case TRANSFORM:
			return new Transform_Ability(ID, ability.getName(),
					ability.getAbilityRange(), ability.getAbilityArea(),
					ability.getAbilityAffect());
		case RETRANSFORM:
			return new Retransform_Ability(ID, ability.getName(),
					ability.getAbilityRange(), ability.getAbilityArea(),
					ability.getAbilityAffect());
		case POISON:
			return new Poison_Ability(ID, ability.getName(),
					ability.getAbilityRange(), ability.getAbilityArea(),
					ability.getAbilityAffect());
		case BURN:
			return new Burn_Ability(ID, ability.getName(),
					ability.getAbilityRange(), ability.getAbilityArea(),
					ability.getAbilityAffect());
		case SLOW:
			return new Slow_Ability(ID, ability.getName(),
					ability.getAbilityRange(), ability.getAbilityArea(),
					ability.getAbilityAffect());
		case MERCY:
			return new Mercy_Ability(ID, ability.getName(),
					ability.getAbilityRange(), ability.getAbilityArea(),
					ability.getAbilityAffect());
		case EPIPHANY:
			return new Epiphany_Ability(ID, ability.getName(),
					ability.getAbilityRange(), ability.getAbilityArea(),
					ability.getAbilityAffect());
		case RESURRECT:
			return new Resurrect_Ability(ID, ability.getName(),
					ability.getAbilityRange(), ability.getAbilityArea(),
					ability.getAbilityAffect());
		case PROMOTE:
			return new Promote_Ability(ID, ability.getName(),
					ability.getAbilityRange(), ability.getAbilityArea(),
					ability.getAbilityAffect());
		case SECOND_CHANCE:
			return new SecondChance_Ability(ID, ability.getName(),
					ability.getAbilityRange(), ability.getAbilityArea(),
					ability.getAbilityAffect());
		case DISABLE:
			return new Disable_Ability(ID, ability.getName(),
					ability.getAbilityRange(), ability.getAbilityArea(),
					ability.getAbilityAffect());
		case STUN:
			return new Stun_Ability(ID, ability.getName(),
					ability.getAbilityRange(), ability.getAbilityArea(),
					ability.getAbilityAffect());
		case SLEEP:
			return new Sleep_Ability(ID, ability.getName(),
					ability.getAbilityRange(), ability.getAbilityArea(),
					ability.getAbilityAffect());
		case SCHOLAR:
			return new Scholar_Ability(ID, ability.getName(),
					ability.getAbilityRange(), ability.getAbilityArea(),
					ability.getAbilityAffect());
		default:
			return new Attack(ID, ability.getName(), ability.getAbilityRange(),
					ability.getAbilityArea(), ability.getAbilityAffect());
		}
	}

	public static Ability abilityInitializer(Ability ability) {
		int ID = ability.getID();
		switch (ID) {
		case BLESS:
			return new Bless_Ability(ID, ability.getName(),
					ability.getAbilityRange(), ability.getAbilityArea(),
					ability.getAbilityAffectTo());
		case CURE:
			return new Cure_Ability(ID, ability.getName(),
					ability.getAbilityRange(), ability.getAbilityArea(),
					ability.getAbilityAffectTo());
		case HASTE:
			return new Haste_Ability(ID, ability.getName(),
					ability.getAbilityRange(), ability.getAbilityArea(),
					ability.getAbilityAffectTo());
		case PRAY:
			return new Pray_Ability(ID, ability.getName(),
					ability.getAbilityRange(), ability.getAbilityArea(),
					ability.getAbilityAffectTo());
		case LIGHTNING:
			return new Lightning_Ability(ID, ability.getName(),
					ability.getAbilityRange(), ability.getAbilityArea(),
					ability.getAbilityAffectTo());
		case FIREBALL:
			return new Fireball_Ability(ID, ability.getName(),
					ability.getAbilityRange(), ability.getAbilityArea(),
					ability.getAbilityAffectTo());
		case EARTHQUAKE:
			return new Earthquake_Ability(ID, ability.getName(),
					ability.getAbilityRange(), ability.getAbilityArea(),
					ability.getAbilityAffectTo());
		case BLIZZARD:
			return new Blizzard_Ability(ID, ability.getName(),
					ability.getAbilityRange(), ability.getAbilityArea(),
					ability.getAbilityAffectTo());
		case DEFEND:
			return new Defend_Ability(ID, ability.getName(),
					ability.getAbilityRange(), ability.getAbilityArea(),
					ability.getAbilityAffectTo());
		case RUN:
			return new Run_Ability(ID, ability.getName(),
					ability.getAbilityRange(), ability.getAbilityArea(),
					ability.getAbilityAffectTo());
		case CHARGE:
			return new Charge_Ability(ID, ability.getName(),
					ability.getAbilityRange(), ability.getAbilityArea(),
					ability.getAbilityAffectTo());
		case CONCENTRATE:
			return new Concentrate_Ability(ID, ability.getName(),
					ability.getAbilityRange(), ability.getAbilityArea(),
					ability.getAbilityAffectTo());
		case FIRST_AID:
			return new FirstAid_Ability(ID, ability.getName(),
					ability.getAbilityRange(), ability.getAbilityArea(),
					ability.getAbilityAffectTo());
		case CURSE:
			return new Curse_Ability(ID, ability.getName(),
					ability.getAbilityRange(), ability.getAbilityArea(),
					ability.getAbilityAffectTo());
		case TRANSFORM:
			return new Transform_Ability(ID, ability.getName(),
					ability.getAbilityRange(), ability.getAbilityArea(),
					ability.getAbilityAffectTo());
		case RETRANSFORM:
			return new Retransform_Ability(ID, ability.getName(),
					ability.getAbilityRange(), ability.getAbilityArea(),
					ability.getAbilityAffectTo());
		case BURN:
			return new Burn_Ability(ID, ability.getName(),
					ability.getAbilityRange(), ability.getAbilityArea(),
					ability.getAbilityAffectTo());
		case SLOW:
			return new Slow_Ability(ID, ability.getName(),
					ability.getAbilityRange(), ability.getAbilityArea(),
					ability.getAbilityAffectTo());
		case POISON:
			return new Poison_Ability(ID, ability.getName(),
					ability.getAbilityRange(), ability.getAbilityArea(),
					ability.getAbilityAffectTo());
		case MERCY:
			return new Mercy_Ability(ID, ability.getName(),
					ability.getAbilityRange(), ability.getAbilityArea(),
					ability.getAbilityAffectTo());
		case EPIPHANY:
			return new Epiphany_Ability(ID, ability.getName(),
					ability.getAbilityRange(), ability.getAbilityArea(),
					ability.getAbilityAffectTo());
		case RESURRECT:
			return new Resurrect_Ability(ID, ability.getName(),
					ability.getAbilityRange(), ability.getAbilityArea(),
					ability.getAbilityAffectTo());
		case PROMOTE:
			return new Promote_Ability(ID, ability.getName(),
					ability.getAbilityRange(), ability.getAbilityArea(),
					ability.getAbilityAffectTo());
		case SECOND_CHANCE:
			return new SecondChance_Ability(ID, ability.getName(),
					ability.getAbilityRange(), ability.getAbilityArea(),
					ability.getAbilityAffectTo());
		case DISABLE:
			return new Disable_Ability(ID, ability.getName(),
					ability.getAbilityRange(), ability.getAbilityArea(),
					ability.getAbilityAffectTo());
		case STUN:
			return new Stun_Ability(ID, ability.getName(),
					ability.getAbilityRange(), ability.getAbilityArea(),
					ability.getAbilityAffectTo());
		case SLEEP:
			return new Sleep_Ability(ID, ability.getName(),
					ability.getAbilityRange(), ability.getAbilityArea(),
					ability.getAbilityAffectTo());
		case SCHOLAR:
			return new Scholar_Ability(ID, ability.getName(),
					ability.getAbilityRange(), ability.getAbilityArea(),
					ability.getAbilityAffectTo());
		default:
			return new Attack(ID, ability.getName(), ability.getAbilityRange(),
					ability.getAbilityArea(), ability.getAbilityAffectTo());
		}
	}

	public final void abilityManager(Army army, AI_Part ai_part,
			boolean isCalculation) {
		if (isCalculation == false) {
			this.mainAct(army, ai_part);
		} else {
			this.calculation(army, ai_part);
		}
	}

	public final void damageToEnemy(Army current, int damage, Army enemy,
			boolean isCalculation) {
		int damageToEnemy;
		if ((damage - enemy.getTotalDefense()) < 0) {
			return;
		} else {
			damageToEnemy = damage - enemy.getTotalDefense();
		}
		int enemy_hp = enemy.getHealth();
		enemy.setHealth(
				enemy_hp
						- (int) ((((float) current.getHealth()) / enemy_hp) * damageToEnemy),
				armyManager, isCalculation);
	}

	public final void act(Army army, Scenario scenario) {
		mainAct(army, scenario);
		afterAct(army, scenario);
	}

	public void afterAct(Army army, Scenario scenario) {
		ArrayList<Army> dead = armyManager.getDeadArmy();
		if (dead.size() > 0) {
			float killGold = army.getKillGold();
			Group group = scenario.getGroup(army.getGroupID());
			for (Army arm : dead) {
				group.setIncome(group.getIncome()
						+ (int) (arm.getGoldRequire() * killGold));
				scenario.removeArmy(arm.getID(), arm.getGroupID(),
						arm.getLocationX(), arm.getLocationY());
			}
		}
	}

	public abstract void mainAct(Army army, Scenario scenario);

	public abstract void calculation(Army army, Scenario scenario);

	public abstract ArrayList<Coordinate> calculateAffectedArea(Army army,
			Scenario scenario);
}
